#pragma once
#include <iostream>
#include <assert.h>
#include <algorithm>
#include <pthread.h>
#include <mutex>
#include <unordered_map>

#include "Fixed_LengthPool.hpp"

// 判断是在什么机器环境下
#ifdef _WIN64
#include <Windows.h>
typedef long long PAGE_ID;
#elif _WIN32
#include <Windows.h>
typedef size_t PAGE_ID;
#elif __linux__
#include <sys/mman.h>
typedef long long PAGE_ID;
#else
//...其他平台
#error "Unsupported operating system"
#endif

void *SystemAlloc(size_t npage)
{
#ifdef _WIN32
    void *addr = VirtualAlloc(nullptr, npage << PAGE_SHIFT, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

#elif __linux__
    void *addr = mmap(nullptr, npage << PAGE_SHIFT, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (addr == nullptr)
        std::bad_alloc();
    return addr;
#else
    //...其他平台
    std::cerr << "Unsupported operating system" << std::endl;
    exit(-1);
#endif
}

class Span;
void SystemFree(Span* span)
{
    void* ptr = (void*)(span->_pageID >> PAGE_SHIFT);
#ifdef _WIN32
    VirtualFree(ptr, 0, MEM_RELEASE);

#elif __linux__ 
    size_t size = (span->_n << PAGE_SHIFT);
    munmap(ptr, size);
#else
    //...其他平台
    std::cerr << "Unsupported operating system" << std::endl;
    exit(-1);
#endif
}

static const size_t NFREELIST = 208;        // 内存块自由链表个数
static const size_t MAX_BYTES = 256 * 1024; // 线程在ThreadCache层申请内存块的最大限制
static const size_t PAGE_SHIFT = 13;
static const size_t NPAGE = 129; // 最大可以申请129-1页空间

class Freelist
{
public:
    // 判空
    bool Empty() { return _freelist == nullptr; }
    // 获取maxSize值
    size_t MaxSize() { return _maxSize; }
    // 获取链表中节点个数
    size_t Num() { return _num; }
    // 获取链表地址
    void *&GetAddress() { return _freelist; }
    // 取出一个节点
    void *PopFront()
    {
        assert(_freelist);
        void *obj = _freelist;
        _freelist = NextObj(obj);
        NextObj(obj) = nullptr;

        _num--;
        return obj;
    }
    // 取出一批节点
    void *PopRange(size_t count)
    {
        void *start = _freelist;
        if (count <= _num)
        {
            void *cur = _freelist;
            while (--count)
            {
                cur = NextObj(cur);
            }
            _freelist = NextObj(cur);
            NextObj(cur) = nullptr;

            _num -= count;
        }
        else
        {
            _freelist = nullptr;
            _num = 0;
        }
        return start;
    }
    // 插入一个节点
    void PushFront(void *ptr)
    {
        assert(ptr);
        NextObj(ptr) = _freelist;
        _freelist = ptr;

        _num++;
    }
    // 插入一批节点
    void PushRange(void *start, void *end, size_t count)
    {
        assert(start);
        NextObj(end) = _freelist;
        _freelist = start;

        _num += count;
    }
    // 将一整块内存，切成若干个小内存块
    void CutSpan(size_t size, size_t bytes)
    {
        size_t count = 1;
        char *start = (char *)_freelist;
        char *end = start + bytes;
        while ((char *)NextObj(start) != end)
        {
            NextObj(start) = start + size;
            start = (char *)NextObj(start);
            count++;
        }
        NextObj(start) = nullptr;

        _num += count;
    }

private:
    void *_freelist;
    size_t _maxSize; // 一次可以申请内存块个数的最大限制
    size_t _num;     // 链表中的节点个数
};

// 页为单位的Span
struct Span
{
    PAGE_ID _pageID = 0;           // 页号
    size_t _n = 0;                 // 页数
    size_t _useCount = 0;          // 正在使用的个数
    size_t objSize = 0;            // 存放的内存块大小
    Freelist *_freelist = nullptr; // 自由链表
    bool _isUse = false;           // 是否在被使用

    Span *_next = nullptr;
    Span *_prev = nullptr;
};

class SpanList
{
public:
    SpanList()
    {
        _head = PageCache::GetInstance()->GetSpanPool().New();
        _head->_next = _head;
        _head->_prev = _head;

        pthread_mutex_init(&_mtx, nullptr);
    }
    // 迭代器
    Span *Begin() { return _head->_next; }
    Span *End() { return _head; }
    // 获取锁
    pthread_mutex_t &GetMtx() { return _mtx; }
    // 判空
    bool Empty() { return _head->_next != _head; }

    // 取出指定Span
    void Erase(Span *span)
    {
        assert(!Empty());
        Span *prevSpan = span->_prev;
        Span *nextSpan = span->_next;

        prevSpan->_next = nextSpan;
        nextSpan->_prev = prevSpan;
        span->_next = nullptr;
        span->_prev = nullptr;
    }
    // 取出头节点的Span
    Span *PopFront()
    {
        Span *curSpan = _head->_next;
        Span *nextSpan = curSpan->_next;

        _head->_next = nextSpan;
        nextSpan->_prev = _head;
        curSpan->_next = nullptr;
        curSpan->_prev = nullptr;

        return curSpan;
    }
    // 放入Span
    void PushFront(Span *span)
    {
        assert(span);
        Span *nextSpan = _head->_next;

        _head->_next = span;
        nextSpan->_prev = span;
        span->_next = nextSpan;
        span->_prev = _head;
    }

private:
    Span *_head = nullptr;
    pthread_mutex_t _mtx;
};

class UtilClass
{
public:
    // 内存对齐函数
    static size_t RoundUp(size_t size)
    {
        assert(size > 0);
        if (size <= 128)
            return _RoundUp(size, 8);
        else if (size <= 1024)
            return _RoundUp(size, 16);
        else if (size <= 8 * 1024)
            return (size, 128);
        else if (size <= 64 * 1024)
            return (size, 1024);
        else if (size <= 256 * 1024)
            return (size, 8 * 1024);
        else
            ; //............大于256KB的情况
    }

    static inline size_t _RoundUp(size_t size, size_t alignNum)
    {
        if (size % alignNum == 0)
        {
            return size;
        }
        else
        {
            return ((size / alignNum + 1) * alignNum);
        }
    }

    // 寻找哈希桶下标函数
    static size_t Index(size_t size)
    {
        assert(size > 0);
        static const size_t array_number[4] = {16, 56, 56, 56};
        if (size <= 128)
            return _Index(size, 8);
        else if (size <= 1024)
            return (_Index(size - 128, 16) + array_number[0]);
        else if (size <= 8 * 1024)
            return (_Index(size - 1024, 128) + array_number[0] + array_number[1]);
        else if (size <= 64 * 1024)
            return (_Index(size - 8 * 1024, 1024) + array_number[0] + array_number[1] + array_number[2]);
        else if (size <= 256 * 1024)
            return (_Index(size - 64 * 1024, 8 * 1024) + array_number[0] + array_number[1] + array_number[2] + array_number[3]);
        else
            ; // 大于256KB的情况
    }

    static inline size_t _Index(size_t size, size_t alignNum)
    {
        if (size % alignNum == 0)
        {
            return (size / alignNum - 1);
        }
        else
        {
            return (size / alignNum);
        }
    }

    // 计算线程内存池一次向中心缓存要多少个内存块
    static inline size_t FetchBlockNum(size_t size)
    {
        // 计算一页能分成多少个内存块，用这个标准把范围定在[2, 512]之间
        size_t num = MAX_BYTES / size;
        if (num < 2)
        {
            num = 2;
        }
        if (num > 512)
        {
            num = 512;
        }
        return num;
    }
    static inline size_t FetchPageNum(size_t size)
    {
        size_t num = FetchBlockNum(size);
        size_t npage = (MAX_BYTES / (size * num));
        return npage == 0 ? 1 : npage;
    }
};